iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
AI Engineering

它說得頭頭是道系列 第 5

# Day 5 — 一行 const 讓整個知識庫變成白畫面,而我以為是三個 bug

  • 分享至 

  • xImage
  •  

昨天講了知識庫最可怕的失敗:它好好地站在那裡,說著已經不成立的話。

今天講另一種失敗,它一點都不可怕,只是很吵:

整個站變成一片白。


我看到的是三件事

當時的狀況是這樣的:

  1. 首頁一片空白,什麼都沒有
  2. Q&A 板沒反應,點下去沒有任何事情發生
  3. 訊息平台那一頁打不開

三個症狀。

而 QA 看到三個症狀時,職業反射是先數數量:這是三個問題,還是一個?

我先說結論——是一個。而且是一行


第一件事:先確定壞的是哪一層

在跳進程式碼之前,得先回答一個更基本的問題:壞掉的是環境、是部署,還是程式?

這三種的症狀可以完全一樣,但處理成本差一個數量級。

而且老實說,我發現得不快。因為我是一邊工作一邊做這個網頁的——看到畫面還在載入,我就先去做別的事。等回頭一看,還是沒有資料。

那一刻才知道不妙。

在正式專案裡,遇到「新版上去之後某個東西怪怪的」,我們有一套固定順序,不靠直覺:

  1. 退版,確認舊版是好的 → 這一步在排除「它本來就壞」。如果舊版也壞,那這根本不是這次改動造成的,方向完全不同。
  2. 把新版重推一次,看還會不會發生 → 這一步在排除「推版過程本身出問題」,例如部署跑到一半被喊停、檔案沒完全更新。
  3. 如果重推之後就正常了 → 那就是部署過程的偶發問題。只要沒有重複發生,通常不需要深追——每次推版都有一定機率碰到,追它的投資報酬率很低。
  4. 如果重推之後還是壞 → 這才確定是程式的問題。接下來才去查程式碼、找衝突、在本機重現,改完再重推。

我想特別講第 3 步,因為它是很多人不敢做的判斷:有些問題是可以決定不追的。

QA 的職責不是把每一個異常都追到底,是知道哪些異常值得追。把時間花在一個不會重複出現的部署偶發事件上,代價是那些真正會重複出現的問題沒有人看。

這一整套的目的只有一個:在開始查程式碼之前,先讓「我看到的東西」變成一個可信的前提。

否則後面所有的推論,都建立在一個你沒驗證過的假設上——而那正是這個系列從第一天就在講的事。


Console 給了一行字

Uncaught ReferenceError: Cannot access 'PAGES' before initialization

這行字很重要,而且它已經把答案講完了——只要你注意到它不是另一句話。

如果訊息是這樣:

Uncaught ReferenceError: PAGES is not defined

那意思是「根本沒有這個東西」——可能是打錯字、檔案沒載到、變數名不對。

但它說的是 Cannot access 'PAGES' before initialization:東西是有的,只是你太早碰它。

這兩句話指向完全不同的方向。而我看過太多人(包括我自己)看到 ReferenceError 就直接跳到「是不是沒定義」——錯誤訊息的後半句,經常比前半句有用。


真正的原因:暫時性死區

程式的形狀大概是這樣:

// 第 153 行
applyLang();                    // ← 這裡面會用到 PAGES

//  ...中間隔了六百多行...

// 第 836 行
const PAGES = { /* 所有頁面的內容 */ };

applyLang() 在第 153 行就被呼叫,而它需要的 PAGES 到第 836 行才宣告。中間隔了 683 行。

這裡有兩個 JavaScript 的機制在打架:

第一,函式宣告會被提升(hoisting)。 所以 applyLang() 寫在後面、在第 153 行叫得動,完全合法。

第二,constlet 也會被提升,但它們在宣告那一行之前處於「暫時性死區」(Temporal Dead Zone, TDZ)。 它們存在,但碰不得——碰了就丟 ReferenceError

這是 const/letvar 最容易被忽略的差別:

console.log(a);   // undefined  ← var 會被提升,而且初始化成 undefined
var a = 1;

console.log(b);   // ReferenceError: Cannot access 'b' before initialization
const b = 1;      // ← const 也被提升了,但在這一行之前是死區

var 給你一個 undefined,讓你帶著錯的值繼續跑;const 直接把你攔下來。

後者其實是好事。 只是這次它攔得有點大。


為什麼壞掉的是三個地方

這才是我真正想講的部分。

一個 <script> 在頂層丟出未被捕捉的錯誤時,整支腳本會停止執行。

所以第 153 行炸掉的那一瞬間,後面的每一行都沒有跑到:

  • 頁面渲染的那段?沒跑 → 白畫面
  • Q&A 板的事件綁定?沒跑 → 點了沒反應
  • 訊息平台那一頁的路由註冊?沒跑 → 打不開

它們不是壞掉了。它們是從來沒有被建立過。

三個症狀、一個原因、一行程式。


所以這篇真正的主題是:症狀數量 ≠ 缺陷數量

如果我當時把它當成三個問題處理,會發生什麼事?

我會開三張卡。三張卡可能被分給不同的人、排進不同的時程,然後各自被「修好」——用三種不同的繞法。而真正那一行,可能到現在還在。

這是 QA 很容易犯、而且代價很高的錯誤,因為它看起來很勤勞。三張卡、三個重現步驟、三份截圖,工作量很飽滿。

我後來把這件事收成一條自己在用的準則:

當多個症狀「同時出現」,優先假設它們共用一個上游。

注意是「同時出現」。如果是陸續出現的,那更可能真的是不同的東西。

但——這裡有一個更重要的補充,而且它是 QA 跟工程師思路的分水嶺:

這個假設必須被驗證,不能只是推論。

驗證方法很簡單:把那一行改掉,三個症狀應該要同時消失。

如果只消失了兩個,那就代表真的還有第二個 bug 躲在後面——而它剛好被第一個 bug 蓋住了,因為腳本根本沒跑到那裡。

我這次是三個一起消失。但我想強調的是:我是驗證過才這樣說的,不是因為我的推論聽起來很合理。


但白畫面其實是好運氣

講完這個 bug,我想講另一種壞法——因為我真的碰過,而且它難處理太多了。

那一次的症狀是:Q&A 板整個當掉。 不能留言、不能發問、不能按讚。

而困難的地方在於:

  • 其他畫面全部正常,是新版、顯示無誤,看起來完全健康
  • 不報錯。沒有紅字、沒有「找不到資料」、沒有任何一行 log
  • 它只是——載入符號一直在那裡轉。

後來查出來是程式衝突。但重點不是原因,是我花了多久才確定它真的壞了

因為那個畫面沒有說「我壞了」。它說的是「我還在載入」。

而「還在載入」跟「網路有點慢」長得一模一樣。

你的第一反應不會是查 bug,是等一下、重新整理、換個時間再看。你會很自然地把它歸給環境,因為所有你看得到的證據都支持那個解釋。

這種 bug 的成本不在修,在發現。

回頭看,白畫面加上一行紅字,其實是好運氣:它吵、它明確、它主動跑來告訴你哪裡不對。

而這也是為什麼前面那個「先排除環境因素」的步驟必須是一套固定動作,而不是憑感覺——因為當一個東西壞得夠安靜,「是不是網路問題」這個念頭會一直是最舒服、也最容易讓你收手的答案。


而這正好是這個系列的縮小版

我想用這件事收掉 Phase 1,因為它跟後面 25 天要處理的問題,結構完全一樣。

這個 bug 我抓得到,靠的是三件事:

  1. 一個明確的錯誤訊息——它告訴我哪個變數、什麼性質的錯
  2. 一份可以打開的原始碼——我可以直接去看第 153 行和第 836 行
  3. 一個乾淨的驗證方式——改掉它,症狀應該同時消失

而接下來要面對的那個問題,這三樣一個都沒有。

一個知識庫答錯的時候,不會有 Console。它不會丟 ReferenceError,不會告訴你是第幾行。它會給你一段語氣自信、格式完整、還附了編號的答案。

它壞掉的樣子,比較像那個一直在轉的載入符號——不是紅字。

差別是:載入符號至少讓你覺得哪裡怪怪的。一段寫得很漂亮的錯答案,不會。

而且它也會有「一個原因、多個症狀」這件事——我在 Phase 2 抓到 8 處錯誤,一開始以為是 8 個各自獨立的問題,後來才發現其中好幾處共用同一個根因

同一套方法,同一種思路,只是那一次沒有 Console 可以看。

那才是真正難的地方。


Phase 1 到這裡結束

回顧這五天:

  • Day 1 — 一段格式正確、術語精準的假規則,騙過了我兩個星期
  • Day 2 — 一百多張卡,兩種看不懂,最後我兩張都是靠問人
  • Day 3 — 十一個問題,一張在寫程式之前就先寫好的驗收表
  • Day 4 — 第一版是靜態網頁,零 AI;還有一個我自己承認還沒做完的驗收
  • Day 5 — 一行 const,三個症狀,和一條「症狀數量不等於缺陷數量」的準則

明天開始 Phase 2,也是這整個系列的核心。

我會讓 AI 幫我把 89 張卡統整成 16 張。它會做得非常好——好到我不安。

然後我會做一件 QA 才會做的事:我去驗證它。


上一篇
# Day 4 — 第一版連一行 AI 都沒有,它是一個靜態網頁
下一篇
# Day 6 — 89 張卡變成 16 張:我讓 AI 幫我做一份「現在長怎樣」的說明書
系列文
它說得頭頭是道6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言